#pragma once

#include <coroutine>
#include <iostream>

namespace HelloWorld {
struct Promise;

// Basic Coroutine
//     promise_type
struct Coroutine {
    using promise_type = Promise;
    
    std::coroutine_handle<promise_type> handle;
    Coroutine(std::coroutine_handle<promise_type> h) : handle(h) {}
    ~Coroutine() {
        if (handle) handle.destroy();
    }
    void resume() {
        if (handle && !handle.done()) handle.resume();
    }
};

// Basic Awaiter
//     await_ready
//     await_suspend
//     await_resume
template<bool Suspend>
struct Awaiter {
    bool await_ready() noexcept {
        std::cout << "Awaiter::await_ready" << std::endl;
        return !Suspend;
    };
    void await_suspend(std::coroutine_handle<Promise>) noexcept {
        std::cout << "Awaiter::await_suspend" << std::endl;
    };
    void await_resume() noexcept {
        std::cout << "Awaiter::await_resume" << std::endl;
    }
};

// Basic Promise
//     get_return_object
//     initial_suspend
//     final_suspend
//     return_void/return_value
//     unhandled_exception
struct Promise {
    Coroutine get_return_object() {
        std::cout << "Promise::get_return_object" << std::endl;
        return Coroutine{std::coroutine_handle<Promise>::from_promise(*this)};
    }
    Awaiter<true> initial_suspend() {
        std::cout << "Promise::initial_suspend" << std::endl;
        return {};
    }
    Awaiter<true> final_suspend() noexcept {
        std::cout << "Promise::final_suspend" << std::endl;
        return {};
    }
    void return_void() {
        std::cout << "Promise::return_void" << std::endl;
    }
    void unhandled_exception() {
        std::cout << "Promise::unhandled_exception" << std::endl;
    }
};

// 函数声明
void Test();
}
